/**
 * 低代码动态变量处理mixin
 */
import EditorTipList from '@/components/common/low-code/low-code-editor-tip-list.js';
import triggers from '@/components/common/low-code/low-code-linkage-triggers.js';
import { executeExp, isExpression, getLowCodeExpVal } from '@/components/common/low-code/low-code-util.js';
import { isArray, isObject, objHas } from '@/utils/util.js';
import { toRaw, watch } from 'vue';

export default {
  data() {
    return {
      clickedData: {}, // 点击时收集的数据
      clickedText: '', // 点击时（自定义）目标值
      expressionWatchs: [],
    };
  },
  watch: {
    chartIsCreated(isCreated) {
      if (isCreated) {
        this.bindLowCodeChartClick();
      }
    },
    'config.config.property'() {
      this.__isProxied = false;
    },
  },
  mounted() {
    this.initXvueProxy();
    this.$el.addEventListener('click', this.lowCodeWidgetClick);
  },
  beforeUnmount() {
    this.$el.removeEventListener('click', this.lowCodeWidgetClick);
  },
  methods: {
    initXvueProxy() {
      let { updateConfigProperty } = this;
      Object.defineProperty(this, 'updateConfigProperty', {
        get: () => {
          if (this.__isProxied) {
            return updateConfigProperty;
          }

          this.xvueProxy(this.config.config.property, this.orgConfig.config.property);
          this.config.config.property = this.xvueProxyObj(this.config.config.property);
          this.__isProxied = true;
          return updateConfigProperty;
        },
        set: newVal => {
          updateConfigProperty = newVal;
        },
      });
    },

    // 给对象做Proxy
    xvueProxyObj(obj) {
      if (isObject(obj)) {
        Object.entries(obj).map(([i, val]) => {
          if (isObject(val) || isArray(val)) {
            obj[i] = this.xvueProxyObj(val);
          }
        });
      } else if (isArray(obj)) {
        for (let i = 0; i < Math.min(obj.length, 50); i++) { // 只处理前面50条，节省内存
          obj[i] = this.xvueProxyObj(obj[i]);
        }
      } else {}

      if (!isObject(obj)) {
        return obj;
      }

      const proxyData = this._xvueProxyObj(obj);
      return proxyData;
    },

    _xvueProxyObj(obj) {
      const _obj = toRaw(obj);
      const proxyData = new Proxy(_obj, {
        get: (target, key, receiver) => {
          if (key.startsWith?.('__')) { // xvue的本身的key，如"__v_isReadonly"
            return target[key];
          }
          if (key === 'dataVal') { // xvueapi数据需要等xvue接口请求完
            return target[key];
          }
          const val = getLowCodeExpVal({ expression: target[key], vm: this });
          return val;
        },
        set: (target, key, value, receiver) => {
          // 判断前后设置前后值是否相等，相同就不要替换，不然表达式会被替换成真值，导致无法响应式
          let isSame = (target[key] === value);
          if (isExpression(target[key])) {
            const oldVal = getLowCodeExpVal({ expression: target[key] });
            if (oldVal === value) {
              isSame = true;
            }
          }

          if (!isSame) {
            Reflect.set(target, key, value, receiver);
          }
          return true;
        },
      });
      return proxyData;
    },

    // 给组件顶层this下面的属性做Object.defineProperty
    xvueProxy(property, orgProperty) {
      this.$vmProxy = this._xvueProxyObj(this);

      const excludeKeys = ['layout', 'pageId'];
      Object.entries(property).map(([i]) => {
        if (excludeKeys.includes(i) || this.$options.computed[i]) {
          return;
        }
        this[i] = this.xvueProxyObj(property[i]);
      });
    },

    // 收集可以在编辑器中自动联想下拉列表属性和方法
    initLowCodeTips() {
      if (this.isDesignView) {
        const compName = this.config.propertyPannelName.replace(`config_${process.env.xvueNameSpace_}`, '');

        let datas = [
          ...EditorTipList.common.datas,
          ...EditorTipList?.[compName]?.datas || [],
        ];
        datas = Array.from(new Set(datas));
        datas.forEach(n => {
          if (this._hasPath(n)) {
            this.addCompExportDataStructByKeyPath?.([n]);
          }
        });

        let methods = [
          ...EditorTipList.common.methods,
          ...EditorTipList?.[compName]?.methods || [],
        ];
        methods = Array.from(new Set(methods));
        methods.forEach(n => {
          if (this._hasPath(n)) {
            this.addCompExportMethod?.([n]);
          }
        });
      }
    },

    _hasPath(pathStr) {
      const paths = pathStr.split('.');
      let obj = this;
      for (let i = 0; i < paths.length; i++) {
        const key = paths[i];
        if (Reflect.has(obj, key)) {
          obj = obj[key];
        } else {
          return false;
        }
      }
      return true;
    },

    _clearLowCodeLockTimer() {
      this.timers.executeTimer = setTimeout(() => {
        this.executeLock = false;
      }, 100);
    },

    // 执行动作
    executeAction(option = '', data = null, config = null) {
      // 传参判断
      let _trigger;
      let _data;
      let _config;
      if (typeof option === 'object') {
        _trigger = option.trigger;
        _data = option.data;
        _config = option.config || this.config;
      } else {
        _data = data;
        _config = config || this.config;
        _trigger = option;
      }

      // 加锁，防止多次触发
      if (_trigger !== 'onClickDiy') {
        if (this.executeLock) {
          this._clearLowCodeLockTimer();
          return;
        }
        this.executeLock = true;
        this._clearLowCodeLockTimer();
      }

      // 空trigger处理
      const compName = _config.propertyPannelName.replace(`config_${process.env.xvueNameSpace_}`, '');
      if (!_trigger) {
        _trigger = triggers?.[compName]?.[0]?.value;
      }
      if (!_trigger) {
        return;
      }

      // 触发数据处理
      if (_data) {
        this.clickedData = _data;
      }

      window.showLog({
        clickedData: this.clickedData,
        clickedText: this.clickedText,
      });

      // 触发动作
      const actions = _config.initiative?.actions?.filter(n => n.trigger === _trigger);
      actions?.forEach(n => {
        if (n.trigger === 'onClickDiy') {
          let els = this.$el.querySelectorAll(n.elSelector);
          const hasEl = [...els].some(n1 => n1 === option.el);
          els = null;
          if (!hasEl) {
            return;
          }
        }

        n.subActions.forEach(n1 => {
          if (n1.actType === 'api') {
            n1.params.forEach(n2 => {
              executeExp(n2.execution);
            });
          }
          executeExp(n1.execution);
        });
      });
    },

    updateParamsxVueApi() {
      // 留空，防止报错
    },

    bindLowCodeChartClick() {
      const chart = this.$refs?.dataChart?.chart;

      chart?.on('click', params => {
        this.bindLowCodeChartClickCallback(params);
      });
    },

    bindLowCodeChartClickCallback(params) {
      // 不需要触发chart的点击事件的组件
      const blankComponents = [`config_${process.env.xvueNameSpace_}chain_comparison_indicator_bar`];
      if (blankComponents.includes(this.config.propertyPannelName)) {
        return;
      }
      const data = JSON.parse(JSON.stringify(params.data || {}));
      delete data.itemStyle;
      delete data.emphasis;
      if (Array.isArray(data)) {
        const lastItem = data[data.length - 1];
        if (typeof lastItem === 'string' && lastItem.startsWith('{"')) {
          data[data.length - 1] = JSON.parse(lastItem);
        }
      }
      this.executeAction('onClick', data);
    },

    lowCodeWidgetClick(e) {
      this.clickedText = e.target.textContent.trim();
      this.executeAction({ trigger: 'onClickDiy', el: e.target });
    },

    addLowCodeWatchs({ srcObj, srcKey }) {
      const item = this.expressionWatchs.find(n => n.srcObj === srcObj && n.srcKey === srcKey);
      if (!item) {
        this.expressionWatchs.push({ srcObj, srcKey });
        watch(()=> srcObj[srcKey], () => {
          clearTimeout(this.timers.lowCodeWatch);
          this.timers.lowCodeWatch = setTimeout(() => {
            this.loadWidget();
          }, 100);
        });
      }
    },

  },
};
